SEP 6 -- 接口重复请求策略
Head
- Author: larry
- Status: draft
- Type: Standards
- Created: 2017-08-28
摘要
解决重复请求导致的数据重复插入。
问题
在创建一个新记录,比如订单创建的时候,用户提交后短时断网或者其他原因,后台已经插入db成功,但是前端页面没有收到响应,用户会认为没有成功,发起重试,这样会导致db中创建了两条相同的订单。类似问题在我们系统中没有正确处理。
导致这种问题的原因是,create接口是在请求完成后才生成唯一的记录ID,请求时没有一个ID可以用来判断重入。相同请求串重复请求,服务器无法知道是老的一笔,还是新的一笔。
思路
要做到相同的串多次调用不产生多条记录,就必须让服务器能识别出多次调用的是同一个串,或者意图是做同一件事。实现思路通常是为每个请求生成一个唯一的序列号,服务器根据这个序列号去判断,先前是否做成功了。
如何生成请求序列号
-
由client为每个请求生成一个请求序列号。
这种方法是最常见的方法,有些下单页面会先生成订单号,这个订单号会在DB中先占用一条记录,后面的创建操作实际上是对这个记录的更新。
先在DB中生成订单号,再来更新的方法,只有在特殊流程才有意义,大多数情况下不适合,尤其是在批量操作中。
由client生成一个请求序列号,能根据业务流程灵活处理,相对比较好处理。缺点是client需要特别处理,而且这个序列号并不是业务的一部分,存不存入数据库会是个问题。
-
后端接口根据请求内容,自动生成一个序列号。
如果是用户反复请求相同的串,后端也可以根据这个请求串做个hash,把这个hash作为请求序列号。但是前提是这个串中有些数据可以唯一识别这次请求,如果不能,则必须由前端增加一个能识别的东西,比如一个随机串。
这种方式需要后端做一些特殊处理,要根据每个业务接口的不同选择不同的字段加入hash,逻辑稍微复杂些,但是client端简单些。
服务器如何处理
-
序列号存储
- 序列号存入业务数据表里:理解起来简单,可以保证绝对去重,但是对业务数据有侵入。
- 序列号放到cache里:cache的时候放一个超时机制,减少cache用量。
-
重复请求的返回
如果重复请求时直接报错,可以在cache中保存hash即可。
做的更好一点,可以在cache中保存业务数据,甚至直接保存上次的返回,重复请求的时候可以不报错,直接返回上次返回的数据,但是这个策略要具体场景看,有些对时间场景敏感的数据,不一定合适,比如重复请求的返回数据可能已经变了。推荐在业务接口中自行处理重入。